<?php

namespace server\impl;

use common\core\server\BaseServer;
use common\helpers\BaseHelper;
use common\helpers\CodeHelper;
use common\helpers\ConstantHelper;
use common\helpers\DictHelper;
use server\dao\EquLine;
use server\dao\EquStation;
use server\dao\Role;
use server\dao\User;
use server\dao\UserToken;
use server\EquipmentInterface;
use server\RoleInterface;
use server\UserInterface;
use Yii;
use yii\base\UserException;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

class UserImpl extends BaseServer implements UserInterface
{
    public $user;
    public $token;
    public $role;
    public $equipment;
    protected $line;
    protected $station;

    public function __construct(RoleInterface $role, EquipmentInterface $equipment, array $config = [])
    {
        $this->user = new User();
        $this->token = new UserToken();
        $this->role = $role;
        $this->equipment = $equipment;
        $this->line = new EquLine();
        $this->station = new EquStation();
        parent::__construct($config);
    }


    /**
     * 登录
     *
     * @param array $params [username, password, 'app_id']
     * @param bool $isApi 是否app登录
     *
     * @return array|mixed|User
     * @throws UserException
     * @throws \yii\base\Exception
     */
    public function login(array $params, $isApi = false)
    {
        $model = $this->user;
        $data = $model->filterParams($params);
        $model->scenario = 'login';
        $model->setAttributes($data);
        // validate
        if (!$model->validate()) {
            return $isApi ? $this->invalidFormException($model->getFirstErrors()) : $model;
        }
        $appId = ArrayHelper::getValue($params, 'app_id', \Yii::$app->id);
        $user = $this->user->getUserOne(['username' => $model->username]);
        if ($isApi) {
            Yii::$app->user->login($user);
            $token = $this->makeToken($user, $appId);
            // 登录日志
            $this->triggerServer(self::EVENT_USER_LOGIN_LOG, ConstantHelper::USER_LOGIN_TYPE_IN);
            // 短信发送
            //$this->triggerServer(self::EVENT_USER_SENDER_SMS, $user);
            // 邮件发送
            //$this->triggerServer(self::EVENT_USER_SENDER_EMAIL, $user);
            return $token;
        } else {
            \Yii::$app->user->login($user, \Yii::$app->params['user.expires_in']);
        }
    }

    /**
     * 生成token
     *
     * @param $user
     * @param $appId
     *
     * @return array
     * @throws \yii\base\Exception
     */
    public function makeToken($user, $appId)
    {
        return $this->token->makeToken($user, $appId);
    }

    /**
     * 注册
     *
     * @param array $params [
     *                      'username',
     *                      'username',
     *                      'password',
     *                      'mobile',
     *                      'gender',
     *                      'email',
     *                      'face',
     *                      ]
     *
     * @param bool $isApi 是否api
     *
     * @return array|mixed
     * @throws \yii\base\Exception
     */
    public function register(array $params, $isApi = false)
    {
        $data = $this->user->filterParams($params);
        $user = $this->user->register($data, $isApi);
        $this->triggerServer(self::EVENT_LOG_OPERATION, $user, $params);
        return $user;
    }


    public function addUser(array $params, $isApi = false)
    {
        $data = $this->user->filterParams($params);
        $user = $this->user->register($data, $isApi);
        $role_data['roles'] = explode(',', $params['roles']);
        $role_data['user_id'] = $user->id;
        $this->role->assign($role_data);
        $this->triggerServer(self::EVENT_LOG_OPERATION, $user, $params);
        return $user;
    }

    public function editUser(array $params, $isApi = false)
    {

        $data = $this->user->filterParams($params);
        if($data['status'] != -1){
            $role_data['roles'] = explode(',', $params['roles']);
            $role_data['user_id'] = $data['id'];
            $this->role->assign($role_data);
        }
        $user = $this->user->getById(\Yii::$app->user->identity->id);
        $this->triggerServer(self::EVENT_LOG_OPERATION, $user, $params);
        return  $this->user->updateByParams($data);
    }

    /**
     * 获取单个用户的数据
     *
     * @return array
     * @throws \Throwable
     */
    public function getUserInfo()
    {
        $user_id = \Yii::$app->user->getIdentity()->id;
        $user = $this->user->getUserOne(['id' => $user_id]);
        $role = $this->role->getRolesByUser($user_id);
        $user_info = $user->attributes;
        //return $role;
        //return $this->role->getChildRolePermission('查询角色');
        //return $a = $this->role->getPermissionsByRole('查询角色');
        $user_info['roles'] = [];
        $role_permission = [];
        foreach ($role as $item) {
            if ($item->name != 'guest') {
                $user_info['roles'][] = $item->name;
                /*$permission = $this->role->getChildRolePermission($item->name);
                foreach ($permission as $key => $value) {
                    $role_permission[$item->name][$item->name][] = $value->name;
                }*/
            }
        }
        //$user_info['role_permission'] = array_values($role_permission);
        $user_info['devices'] = [];
        if ($user_info['username'] === 'admin') {
            $line = $this->equipment->lineList();
            $line_ids = array_column($line, 'id');
        } else {
            $line_ids = explode(',', $user_info['line_ids']);
        }
        $station = $this->equipment->stationList([]);
        if (!empty($line_ids) && !empty($station)) {
            foreach ($line_ids as $id) {
                //TODO 显示所管理的线路
                $line_item = $this->line->getById($id);
                $station = $this->station->getStationList(['line_id' => $id]);
                $user_info['devices'][] = ['id' => $id, 'name' => $line_item->name, 'station' => $station];
                // $user_info['devices'][]['station'] = [];
            }
        }

        return $user_info;
    }

    /**
     * 获得用户列表
     *
     * @param array $params [
     *                      'username',
     *                      'username',
     *                      'mobile',
     *                      'gender',
     *                      'email',
     *                      'created_at',
     *                      'updated_at',
     *                      ]
     * @param bool $isAll
     *
     * @return array
     */
    public function getUserList(array $params, $isAll = false)
    {
        $gender = DictHelper::getGenderType(false);
        $data = $this->user->getUserList($params, $isAll);
        return $this->htmlSpecialChars($data, [
            'line_name',
            'roles'
        ], [
            'line_name' => function ($data) {
                $line_ids = explode(',', $data['line_ids']);
                $lines = $this->line->getLineByIds($line_ids);
                $line_names = array_column($lines, 'name');
                return implode(',', $line_names);
            },
            'roles' => function ($data) {
                $role_array = [];
                $role = $this->role->getRolesByUser($data['id']);
                foreach ($role as $item) {
                    if ($item->name != 'guest') {
                        $role_array[] = $item->name;
                        /*$permission = $this->role->getChildRolePermission($item->name);
                        foreach ($permission as $key => $value) {
                            $role_permission[$item->name][$item->name][] = $value->name;
                        }*/
                    }
                }
                return implode(',', $role_array);
            },
        ]);
    }

    /**
     * 刷新token
     *
     * @param $refreshToken
     *
     * @return array
     * @throws UserException
     * @throws \yii\base\Exception
     */
    public function refreshToken($refreshToken)
    {
        $userToken = $this->token->refreshToken($refreshToken);
        if (empty($userToken)) {
            $this->invalidParamException('', CodeHelper::TOKEN_INVALID);
        }
        return $this->token->makeToken($userToken->user, \Yii::$app->id);
    }

    /**
     * 忘记密码
     *
     * @param array $params
     *
     * @return mixed
     * @throws \yii\base\Exception
     */
    public function forgetPassword(array $params)
    {
        $user = $this->user->getUserOne([
            'username' => $params['username'],
        ]);
        $user->scenario = 'changePassword';
        $user->updateByParams($params);
        return $user;
    }

    /**
     * 修改密码
     *
     * @param array
     *
     * @return mixed
     * @throws \yii\base\Exception
     */
    public function changePassword(array $params)
    {
        if ($params['repassword'] != $params['newpassword']) {
            return $this->invalidParamException('两次新密码不一致');
        }
        $user_id = \Yii::$app->user->identity->id;
        $user = $this->user->findIdentity($user_id);
        $user->scenario = 'changePassword';
        if (empty($user)) {
            $this->invalidParamException('没有此账户');
        }

        if (!$user->validatePassword($params['password'], $user->password_hash)) {
            $this->invalidParamException('旧密码不正确');
        }
        $tmp['id'] = $user_id;
        $tmp['password_hash'] = \Yii::$app->security->generatePasswordHash($params['newpassword']);
        return $this->user->updateByParams($tmp);
    }

    /**
     * 重置密码
     *
     * @param $user_id
     *
     * @return mixed
     * @throws UserException
     * @throws \yii\base\Exception
     * @throws \yii\base\InvalidConfigException
     * @throws \yii\db\Exception
     */
    public function resetPassword($user_id)
    {
        $user = $this->user->findIdentity($user_id);
        if (empty($user)) {
            $this->invalidRequestException('没有此账户');
        }
        $user->scenario = 'resetPassword';
        $tmp['id'] = $user->id;
        //$tmp['username'] = $user->username;
        $tmp['password_hash'] = \Yii::$app->security->generatePasswordHash('123456qweasd');
        return $this->user->updateByParams($tmp);
    }

}
